/*******************************************************************************
* Copyright (c) 2010, 2018 西安秦晔信息科技有限公司
* Licensed under the Apache License, Version 2.0 (the "License");
*    you may not use this file except in compliance with the License.
*    You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
*    Unless required by applicable law or agreed to in writing, software
*    distributed under the License is distributed on an "AS IS" BASIS,
*    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*    See the License for the specific language governing permissions and
*    limitations under the License.
*******************************************************************************/
package com.qinyeit.serviceapp.service.materials.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.qinyeit.serviceapp.entity.DishesUnit;
import com.qinyeit.serviceapp.entity.Material;
import com.qinyeit.serviceapp.entity.MaterialCategory;
import com.qinyeit.serviceapp.entity.PurchaseSpec;
import com.qinyeit.serviceapp.entity.enums.*;
import com.qinyeit.serviceapp.exception.BusinessRunTimeException;
import com.qinyeit.serviceapp.repository.materials.MaterialRepository;
import com.qinyeit.serviceapp.repository.materials.PurchaseSpecRepository;
import com.qinyeit.serviceapp.service.branchs.BranchDataServiceImpl;
import com.qinyeit.serviceapp.service.dishes.DishesUnitService;
import com.qinyeit.serviceapp.service.materials.MaterialCategoryService;
import com.qinyeit.serviceapp.service.materials.MaterialService;
import com.qinyeit.serviceapp.service.materials.MaterialUnitService;
import com.qinyeit.serviceapp.service.materials.PurchaseSpecService;
import com.qinyeit.serviceapp.utils.Lang;
import com.qinyeit.serviceapp.utils.LocalUtils;
import com.qinyeit.serviceapp.utils.SearchUtils;
import com.qinyetech.springstage.core.date.DateUtils;
import com.qinyetech.springstage.core.entity.search.SearchFilterHelper;
import com.qinyetech.springstage.core.entity.search.SearchOperator;
import com.qinyetech.springstage.core.entity.search.Searchable;
import com.qinyetech.springstage.core.lang.QyMap;
import com.qinyetech.springstage.core.repository.jdbc.PageNamedParameterJdbcTemplate;
import com.qinyetech.springstage.core.service.BaseService;
import com.qinyetech.springstage.core.utils.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/** 
 * ClassName: MaterialServiceImpl <br/> 
 * Function: 物品管理 业务实现 <br/> 
 * date: 2018-11-07 11:42:52 <br/> 
 * 
 * @author liuwenjin
 * @version 1.0
 * @since JDK 1.8
 */
@Slf4j
@Service
@Transactional
public class MaterialServiceImpl extends BaseService<Material, Long> implements MaterialService {


	@Autowired
	private MaterialRepository materialRepository;
	@Autowired
	private PurchaseSpecRepository purchaseSpecRepository;
	@Autowired
	private PurchaseSpecService purchaseSpecService;
	@Autowired
	private PageNamedParameterJdbcTemplate jdbcTemplate;
	@Autowired
	private MaterialUnitService materialUnitService;
	@Autowired
	private BranchDataServiceImpl branchDataService;
	@Autowired
	private MaterialCategoryService materialCategoryService;
	@Autowired
	private DishesUnitService dishesUnitService;

	@Override
	public QyMap saveData(JSONObject json,Long merchantGroupId) {

		JSONObject materialJson=json.getJSONObject("material");

		Searchable searchable;

		Material copy;
		if(materialJson.containsKey("id") && StringUtils.isNotBlank(materialJson.getString("id"))){
//			searchable = SearchUtils.newSearchableWithMerchantFilter(merchantGroupId);
//			searchable.addSearchParam("id_eq", materialJson.getLong("id"));
//			copy = super.findOne(searchable);
			copy = this.findById(materialJson.getLong("id"));
			copy.setUpdateTimestamp(DateUtils.current());
			purchaseSpecRepository.deleteByMaterialId(copy.getId());
		}else{
			copy = new Material();
			copy.setUuid(LocalUtils.getUUID());
			copy.setUpdateTimestamp(DateUtils.current());
		}
		JSONArray purchaseJson=json.getJSONArray("purchase");

		if(StringUtils.isNotBlank(materialJson.getString("orderType"))){
			OrderType orderType=OrderType.valueOf( materialJson.getString("orderType"));
			copy.setOrderType(orderType);
		}
		if(materialJson.getString("state")!=null){
			State state= State.valueOf(materialJson.getString("state"));
			copy.setState(state);
		}
		if(materialJson.getString("stocktakeType")!=null){
			InventoryType stocktakeType=InventoryType.valueOf(materialJson.getString("stocktakeType"));
			copy.setStocktakeType(stocktakeType);
		}
		if(materialJson.getString("storeMode")!=null){
			StoreMode storeMode= StoreMode.valueOf(materialJson.getString("storeMode"));
			copy.setStoreMode(storeMode);
		}

		copy.setCategory(new MaterialCategory(materialJson.getLong("category")));
		copy.setConsumeRates(materialJson.getDouble("consumeRates"));
		copy.setConsumeUnit(materialJson.getString("consumeUnit"));
		//保存单位
		this.saveUnit(materialJson.getString("consumeUnit"),merchantGroupId,materialJson.getLong("storeId"));
		copy.setGoodsSpec(materialJson.getString("goodsSpec"));
		copy.setMinStock(materialJson.getDouble("minStock"));
		copy.setPinyin(materialJson.getString("pinyin"));
		copy.setName(materialJson.getString("name"));
		copy.setNo(materialJson.getString("no"));
		copy.setSpell(materialJson.getString("spell"));

		copy.setUnit(materialJson.getString("unit"));
		//保存单位
		this.saveUnit(materialJson.getString("unit"),merchantGroupId,materialJson.getLong("storeId"));

		copy.setPurchaseNewPrice(materialJson.getDouble("purchaseNewPrice"));
		copy.setOrderPriceBom(materialJson.getDouble("orderPriceBom"));
		copy.setMaxStock(materialJson.getDouble("maxStock"));
		copy.setCode(materialJson.getString("codes"));
		copy.setMerchantGroupId(merchantGroupId);
		//原料类型 和 菜品库
		copy.setMaterialType(MaterialType.valueOf(materialJson.getString("materialType")));
		if(StringUtils.isBlank(materialJson.getString("storeId"))){
			copy.setStoreId(null);
			//将原料关联的类别共享
			MaterialCategory category = materialCategoryService.findById(materialJson.getLong("category"));
			category.setStoreId(null);
			materialCategoryService.update(category);
		}else {
			copy.setStoreId(materialJson.getLong("storeId"));
			MaterialCategory category = materialCategoryService.findById(materialJson.getLong("category"));
			String sql = "SELECT count(*) as count from materials where category_id = :categoryId and merchant_group_id = :merchantGroupId and store_id is null and id != :materialId";
			QyMap param = QyMap.map("categoryId",category.getId()).setv("merchantGroupId",merchantGroupId).setv("materialId",copy.getId());
			long count = jdbcTemplate.queryForScalar(sql,param,Long.class);
			log.info("--------------------count : {}",count);
			if(count<=0){
				log.info("ccccccccc : {}",materialJson.getLong("storeId"));
				category.setStoreId(materialJson.getLong("storeId"));
			}
		}
		copy=this.save(copy);
		log.info(">>>>>>>>>>>>Vvvvvvvvvvvvvv");

		//保存多采购规格
		QyMap map= savePurchaseSpecs(merchantGroupId, copy, purchaseJson);
		log.info(">>>>>>>>>>>>>>>____------- map : {}",map);
		if(CollectionUtils.isEmpty(map.getList("ids",Long.class))){
			throw new BusinessRunTimeException("采购规格添加失败",10001);
		}
		return map;
	}

	@Override
	public QyMap savePurchaseSpecs(Long merchantGroupId, Material material, JSONArray purchaseJson) {
		Searchable searchable;
		PurchaseSpec current;
		//得到第一条原料的uuid
		List<PurchaseSpec> specList = Lists.newArrayList();
		List<Long> ids = Lists.newArrayList();
		for(int i=0;i<purchaseJson.size();i++){
			JSONObject jsonObject= purchaseJson.getJSONObject(i);
			if (jsonObject.containsKey("id") && jsonObject.getLong("id") != null) {
//				searchable = SearchUtils.newSearchableWithMerchantFilter(merchantGroupId);
//				searchable.addSearchParam("id_eq", jsonObject.getLong("id"));
				current = purchaseSpecService.findById(jsonObject.getLong("id"));
				if (current == null) {
					current=new PurchaseSpec();
				}
			}else{
				current=new PurchaseSpec();
			}
			log.info("ddddddddddddddddd");
//			current=new PurchaseSpec();
			current.setDeleted(false);
			current.setMerchantGroupId(material.getMerchantGroupId());
//			current.setMaterial(material);
			current.setName(jsonObject.getString("purchaseSpec"));
			current.setPrice(jsonObject.getDouble("purchasePrice"));
			current.setUnit(jsonObject.getString("purchaseUnit"));
			if(jsonObject.getBoolean("hasDef")!=null){
				current.setHasDef(jsonObject.getBoolean("hasDef"));
			}else {
				current.setHasDef(false);
			}
			//保存单位
			this.saveUnit(jsonObject.getString("purchaseUnit"),merchantGroupId,material.getStoreId());
			current.setRatio(jsonObject.getDouble("purchaseCount"));
//			purchaseSpecService.save(current);
			specList.add(current);
		}

		List<PurchaseSpec> specs = purchaseSpecRepository.saveAll(specList);
		if(CollectionUtils.isNotEmpty(specs)){
			specs.forEach(x->{
				ids.add(x.getId());
			});
		}
		return QyMap.map("ids",ids).setv("materialId",material.getId());

	}

	@Override
	public void savePurchaseMaterial(List<Long> ids,Long materialId){
		if(CollectionUtils.isEmpty(ids) || materialId==null){
			return;
		}
		String sql = "update purchase_specs set material_id = :material_id where id in(:ids)";
		QyMap map = QyMap.map("material_id",materialId)
				.setv("ids",ids);
		jdbcTemplate.update(sql,map);
	}

	@Override
	public Page<Map<String, Object>> getMaterialsForOut(Long merchantGroupId,Searchable searchable, Long warehouseId, String keywords, Long categoryId,String inventoryType,Boolean pandian,Long storeId) {
		if (merchantGroupId==null){
			return null;
		}
		if(warehouseId==null){
			throw new BusinessRunTimeException("请选择仓库",10001);
		}
		QyMap params= QyMap.NEW();
		params.setv("merchantGroupId",merchantGroupId);
		params.setv("warehouseId",warehouseId);
		String sql = "SELECT m.id as material_id,m.no AS material_no, m.name AS matrial_name, m.pinyin AS matrial_pinyin, m.spell AS material_spell, " +
				"m.unit AS material_unit,m.code as material_code,m.state,\n" +
				" m.goods_spec, c.name AS category_name,c.id as category_id, s.cost, s.count, s.amount\n" +
				"FROM stocks s\n" +
				"\tLEFT JOIN materials m ON m.id = s.material_id \n" +
				"\tLEFT JOIN material_categorys c ON c.id = m.category_id\n" +
				"WHERE s.is_deleted = 0\n" +
				"\tAND s.merchant_group_id = :merchantGroupId  and s.warehouse_id=:warehouseId " ;
		if (storeId!=null){
			sql += " and (m.store_id=:store_id or m.store_id is null)";
			params.setv("store_id",storeId);
		}

		QyMap map = this.getMaterialsForParams(keywords,categoryId,inventoryType,pandian);
		if(StringUtils.isNotBlank(map.getString("sql"))){
			sql += map.getString("sql");
			params.putAll(map.getAs("params",QyMap.class));
		}

		//分页信息
		//page 从0开始
		Pageable pageable= PageRequest.of(searchable.getPage().getPageNumber(),searchable.getPage().getPageSize());//第1页，每页5条
		Page<Map<String,Object>> result= jdbcTemplate.queryForList(sql,params,pageable);
		if(CollectionUtils.isNotEmpty(result.getContent())){
			QyMap param = null;
			for (Map<String, Object> item : result.getContent()) {
				param = QyMap.WRAP(item);
				log.info("code {}",param.getString("material_code"));
				item.put("codes",param.getString("material_code"));
				if(StringUtils.isNotBlank(param.getString("material_code"))){

					//取一个编码
					if(param.getString("code").indexOf(","+keywords+",")!=-1){
						item.put("goodcode",keywords);
					}else {
						item.put("goodcode",param.getString("material_code").substring(1,param.getString("material_code").indexOf(",",2)));
					}
					//将编码逗号分隔为数组
					item.put("goodcodes",StringUtils.split(param.getString("material_code"),","));
				}else {
					item.put("goodcode","");
					item.put("goodcodes",null);
				}
			}
		}
		return result;
	}

	@Override
	public List<Map<String, Object>> getMaterialsForPandian(Searchable searchable,Long merchantGroupId, Long warehouseId, String keywords, Long categoryId, String inventoryType, Boolean pandian,Long storeId) {
		if (merchantGroupId==null){
			return null;
		}
		if(warehouseId==null){
			throw new BusinessRunTimeException("请选择仓库",10001);
		}
		if(storeId==null){
			throw new BusinessRunTimeException("请选择商品原料库",10001);
		}

		QyMap params= QyMap.NEW();
		params.setv("merchantGroupId",merchantGroupId);
		params.setv("warehouseId",warehouseId);
		params.setv("storeId",storeId);
		String sql = "SELECT m.id as material_id,m.no AS material_no, m.name AS matrial_name, m.pinyin AS matrial_pinyin, m.spell AS material_spell, " +
				"m.unit AS material_unit,m.code as material_code\n" +
				"\t, m.goods_spec, c.name AS category_name,c.id as category_id, s.cost, s.count, s.amount\n" +
				"FROM stocks s\n" +
				"\tLEFT JOIN materials m ON m.id = s.material_id\n" +
				"\tLEFT JOIN material_categorys c ON c.id = m.category_id\n" +
				"WHERE s.is_deleted = 0\n" +
				"\tAND s.merchant_group_id = :merchantGroupId  and s.warehouse_id=:warehouseId " +
				"and (m.store_id=:storeId or m.store_id is null)" ;
		QyMap map = this.getMaterialsForParams(keywords,categoryId,inventoryType,pandian);
		if(StringUtils.isNotBlank(sql)){
			sql += map.getString("sql");
			params.putAll(map.getAs("params",QyMap.class));
		}
		log.info("参数 ： {}", JSON.toJSONString(params));
//		Searchable searchable = Searchable.newSearchable();
//		searchable.setPage(0,15);

	     Page<Map<String,Object>> mapPage =jdbcTemplate.queryForList(sql,params,searchable.getPage());
		List<Map<String,Object>>  mapList = mapPage.getContent();

		if(CollectionUtils.isNotEmpty(mapList)){
			QyMap param = null;
			for (Map<String, Object> item : mapList) {
				param = QyMap.WRAP(item);
				log.info("code {}",param.getString("material_code"));
				item.put("codes",param.getString("material_code"));
				if(StringUtils.isNotBlank(param.getString("material_code"))){
					//取一个编码
					if(param.getString("code").indexOf(","+keywords+",")!=-1){
						item.put("goodcode",keywords);
					}else {
						item.put("goodcode",param.getString("material_code").substring(1,param.getString("material_code").indexOf(",",2)));
					}
					//将编码逗号分隔为数组
					item.put("goodcodes",StringUtils.split(param.getString("material_code"),","));
				}else {
					item.put("goodcode","");
					item.put("goodcodes",null);
				}
			}
		}
		return mapList;
	}

	@Override
	public Material getMaterialByUUid(String uuid,Long merchantGroupId) {
		Searchable searchable = SearchUtils.newSearchableWithMerchantFilter(merchantGroupId);
		searchable.addSearchParam("uuid_eq",uuid);
		Material material = this.findOne(searchable);
		return material;
	}

	@Override
	public String getNextNo(String defNo,Long merchantGroupId) {
		String sql = "SELECT no FROM materials WHERE merchant_group_id=:merchantGroupId and is_deleted=false ORDER BY id DESC LIMIT 1";
		QyMap param = QyMap.map("merchantGroupId",merchantGroupId);
		List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql,param);
		if(CollectionUtils.isNotEmpty(maps)){
			Map<String, Object> map = maps.get(0);
			if(map.containsKey("no")){
				String lastNo = map.get("no").toString();
				return Lang.getNextNo(lastNo);
			}
		}
		return defNo;
	}

    @Override
    public List<MaterialCategory> getMaterialByStoreId(Long storeId, Long authenticatedMerchantGroupID) {
		Searchable searchable = SearchUtils.newSearchableWithMerchantFilter(authenticatedMerchantGroupID);
		searchable.addSearchFilter(SearchFilterHelper.or(
				SearchFilterHelper.newCondition("storeId", SearchOperator.eq,storeId),
				SearchFilterHelper.newCondition("storeId",SearchOperator.isNull,null)
		));
		searchable.addSearchParam("parentId_eq",0L);
		searchable.addSearchFilter("dishesCategoryId",SearchOperator.isNull,null);
		List<MaterialCategory> categoryList = materialCategoryService.findWithSort(searchable);

		log.info("--------------- : {}",JSON.toJSONString(categoryList));
		if(CollectionUtils.isEmpty(categoryList)){
			return Lists.newArrayList();
		}
		//一级类别
		String sql = "";
		QyMap param = null;
		List<Map<String,Object>> categoryIds = null;
		List<Long> ids = Lists.newArrayList(); //二级类别id
		List<Material> materialList = null;
		for (MaterialCategory category : categoryList) {
			ids = Lists.newArrayList();
			//查询父级类别下的子类别
			sql = "SELECT id from material_categorys where parent_id = :parent_id";
			param = QyMap.map("parent_id",category.getId());
			categoryIds = jdbcTemplate.queryForList(sql,param);
			//查询类别下的原料信息
			searchable = SearchUtils.newSearchableWithMerchantFilter(authenticatedMerchantGroupID);
			searchable.addSearchFilter(SearchFilterHelper.or(
					SearchFilterHelper.newCondition("storeId", SearchOperator.eq,storeId),
					SearchFilterHelper.newCondition("storeId",SearchOperator.isNull,null)
			));
			if(CollectionUtils.isNotEmpty(categoryIds)){
				ids = categoryIds.stream().map(x->Long.valueOf(x.get("id").toString())).collect(Collectors.toList());
			}
			//一级类别
			ids.add(category.getId());
			log.info("idsc:::::::::::::: {}",ids);
			searchable.addSearchFilter("category.id",SearchOperator.in,ids);
			materialList = this.findWithSort(searchable);
			category.setMaterials((JSONArray) JSONUtils.include(materialList,"id","no","name","pinyin","spell","categoryId","goodsSpec","unit","minStock","maxStock","storeMode","purchaseNewPrice","consumeUnit","consumeRates","orderPriceBom","orderType","stocktakeType","state","materialType"));
		}

		categoryList = categoryList.stream().filter(x->CollectionUtils.isNotEmpty(x.getMaterials())).collect(Collectors.toList());
		return categoryList;
    }


	/**
	 * 搜索
	 * @param keywords 关键字 原料名称/编号/简码/拼音码
	 * @param categoryId 类别
	 * @param inventoryType 盘点类型
	 * @param pandian 是否盘点
	 * @return
	 */
    private QyMap getMaterialsForParams(String keywords, Long categoryId, String inventoryType, Boolean pandian){
		String sql = "";
		QyMap params = QyMap.NEW();
		if(categoryId!=null){
			sql += " and (c.id = :categoryId or c.parent_ids LIKE :parentIds)";
			params.setv("categoryId",categoryId);
			params.setv("parentIds","%/"+categoryId+"/%");
		}
		if(StringUtils.isNotBlank(keywords)){
			sql += " and (m.name LIKE :name OR m.no LIKE :no OR m.pinyin LIKE :pinyin OR m.spell LIKE :spell or m.code like :code)";
			params.setv("no","%"+keywords+"%");
			params.setv("name","%"+keywords+"%");
			params.setv("pinyin","%"+keywords+"%");
			params.setv("spell","%"+keywords+"%");
			params.setv("code","%,"+keywords+"%");
		}
		if(pandian !=null && pandian){
			if(StringUtils.isBlank(inventoryType)){
				throw new BusinessRunTimeException("请选择盘点类型",10002);
			}else {
				if(StringUtils.isNotBlank(inventoryType)){
					sql+=" and m.stocktake_type=:inventoryType";
					params.setv("inventoryType",inventoryType);
				}
			}
		}

		QyMap map = QyMap.map("sql",sql).setv("params",params);

		return map;
	}


	private void saveUnit(String unit,Long merchantGroupId,Long storeId){

		if(StringUtils.isNotBlank(unit)){
			boolean boo = dishesUnitService.exists(SearchUtils.buildExists(null, "name", unit,merchantGroupId));
			if(!boo){
				//不存在 保存单位
				DishesUnit dishesUnit = new DishesUnit();
				dishesUnit.setName(unit);
//				dishesUnit.setNo(DateUtils.format(new Date(),"yyyyMMddHHmmss"));
				dishesUnit.setStoreId(storeId);
				dishesUnit.setState(State.NORMAL);
				dishesUnit.setUuid(LocalUtils.getUUID());
				dishesUnit.setUpdateTimestamp(DateUtils.current());
				dishesUnit.setMerchantGroupId(merchantGroupId);
				dishesUnitService.save(dishesUnit);
			}
			/*if(!boo){
				//不存在 保存单位
				MaterialUnit materialUnit = new MaterialUnit();
				materialUnit.setName(unit);
				materialUnit.setNo(DateUtils.format(new Date(),"yyyyMMddHHmmss"));
				materialUnit.setState(State.NORMAL);
				materialUnit.setUuid(LocalUtils.getUUID());
				materialUnit.setUpdateTimestamp(DateUtils.current());
				materialUnit.setMerchantGroupId(merchantGroupId);
				materialUnitService.save(materialUnit);
			}*/
		}
	}
}